package com.wang.tool.executor;


import com.wang.tool.executor.transitivethreadcontext.ThreadContextTransferTool;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Description 全局线程池管理
 * @see ThreadContextTransferTool#addGlobalTransmitter 上下文切换
 * @Author shaopeng
 * @Date 2022/9/5
 * @Version 1.0
 */
public class ExecutorFactory {

    private static final Map<String, Meta> EXECUTORS = new HashMap<>();

    /**
     * 取
     *
     * @param executorName
     * @return
     */
    public static ExecutorService getExecutor(ExecutorName executorName) {
        if (executorName == null) {
            return null;
        }
        Meta meta = EXECUTORS.get(executorName.getName());
        return meta == null ? null : meta.getWrapper();
    }

    /**
     * 取
     *
     * @param name
     * @return
     */
    public static ExecutorService getExecutor(String name) {
        Meta meta = EXECUTORS.get(name);
        return meta == null ? null : meta.getWrapper();
    }


    /**
     * 取源
     *
     * @param executorName
     * @return
     */
    public static ThreadPoolExecutor getSourceExecutor(ExecutorName executorName) {
        if (executorName == null) {
            return null;
        }
        return getSourceExecutor(executorName.getName());
    }

    /**
     * 取源
     *
     * @param name
     * @return
     */
    public static ThreadPoolExecutor getSourceExecutor(String name) {
        Meta meta = EXECUTORS.get(name);
        return meta == null ? null : meta.getSource();
    }

    /**
     * 注册 不允许重复注册
     *
     * @param executorName
     * @param source
     * @param wrapper
     */
    public static void register(ExecutorName executorName, ThreadPoolExecutor source, ExecutorService wrapper) {
        if (executorName == null) {
            throw new IllegalArgumentException("executorName can not be null");
        }
        register(executorName.getName(), source, wrapper);
    }


    /**
     * 注册 不允许重复注册
     *
     * @param name
     * @param source
     * @param wrapper
     */
    public synchronized static void register(String name, ThreadPoolExecutor source, ExecutorService wrapper) {
        if (name == null || source == null || wrapper == null) {
            throw new IllegalArgumentException("name/source/wrapper can not be null");
        }
        if (EXECUTORS.containsKey(name)) {
            throw new IllegalArgumentException("executor:" + name + " is already");
        }
        EXECUTORS.put(name, new Meta(source, wrapper));
    }

    /**
     * 重新注册
     *
     * @param name
     * @param source
     * @param wrapper
     */
    public synchronized static void reRegister(String name, ThreadPoolExecutor source, ExecutorService wrapper) {
        if (name == null || source == null || wrapper == null) {
            throw new IllegalArgumentException("name/source/wrapper can not be null");
        }
        Meta meta = EXECUTORS.get(name);
        //注册
        EXECUTORS.put(name, new Meta(source, wrapper));
        if (meta == null) {
            return;
        }
        //关闭老的
        meta.getWrapper().shutdown();
        if (!meta.getSource().isShutdown()) {
            meta.getSource().shutdown();
        }
    }

    /**
     * 解注册
     *
     * @param name
     */
    public synchronized static void unregister(String name) {
        EXECUTORS.remove(name);
    }


    /**
     * 修改容量
     *
     * @param name
     * @param coreSize
     * @param maxSize
     * @return
     */
    public static ExecutorStatus changeSize(String name, Integer coreSize, Integer maxSize) {
        ThreadPoolExecutor executor = getSourceExecutor(name);
        if (executor == null) {
            throw new IllegalArgumentException("not find executor:" + name);
        }
        if (coreSize != null && coreSize > 0) {
            executor.setCorePoolSize(coreSize);
        }
        if (maxSize != null && maxSize > 0) {
            executor.setMaximumPoolSize(maxSize);
        }
        return buildExecutorStatus(executor);
    }

    /**
     * 修改回收机制
     *
     * @param name
     * @param keepAlive
     * @param recycleCoreThread
     * @return
     */
    public static ExecutorStatus changeRecycle(String name, Integer keepAlive, Boolean recycleCoreThread) {
        ThreadPoolExecutor executor = getSourceExecutor(name);
        if (executor == null) {
            throw new IllegalArgumentException("not find executor:" + name);
        }
        if (keepAlive != null && keepAlive > 0) {
            executor.setKeepAliveTime(keepAlive, TimeUnit.SECONDS);
        }
        if (recycleCoreThread != null) {
            executor.allowCoreThreadTimeOut(recycleCoreThread);
        }
        return buildExecutorStatus(executor);
    }

    /**
     * 修改拒绝策略
     *
     * @param name
     * @param handler
     * @return
     */
    public static ExecutorStatus changeRejectHandler(String name, RejectedExecutionHandler handler) {
        ThreadPoolExecutor executor = getSourceExecutor(name);
        if (executor == null) {
            throw new IllegalArgumentException("not find executor:" + name);
        }
        if (handler != null) {
            executor.setRejectedExecutionHandler(handler);
        }
        return buildExecutorStatus(executor);
    }


    /**
     * 取状态
     *
     * @param name
     * @return
     */
    public static ExecutorStatus getStatus(ExecutorName name) {
        return buildExecutorStatus(getSourceExecutor(name));
    }

    /**
     * 取状态
     *
     * @param name
     * @return
     */
    public static ExecutorStatus getStatus(String name) {
        return buildExecutorStatus(getSourceExecutor(name));
    }


    /**
     * 取全状态
     */
    public static Map<String, ExecutorStatus> getAllStatus() {
        Map<String, ExecutorStatus> result = new LinkedHashMap<>();
        for (Map.Entry<String, Meta> entry : EXECUTORS.entrySet()) {
            String name = entry.getKey();
            ExecutorStatus status = buildExecutorStatus(entry.getValue().getSource());
            if (status == null) {
                continue;
            }
            result.put(name, status);
        }
        return result;
    }

    /**
     * 取所有
     * @return
     */
    public static Set<String> getAllNames(){
        return new HashSet<>(EXECUTORS.keySet());
    }

    /**
     * 取配置
     * @param name
     * @return
     */
    public static Meta getMeta(String name){
        return EXECUTORS.get(name);
    }

    /**
     * 停止线程池
     * @param name
     */
    public static void shutdown(String name){
        Meta meta = EXECUTORS.get(name);
        if (meta == null) {
            return;
        }
        //关闭老的
        meta.getWrapper().shutdown();
        if (!meta.getSource().isShutdown()) {
            meta.getSource().shutdown();
        }
    }

    /**
     *
     * @param name
     */
    public static void shutdownAndUnregister(String name){
        Meta meta = EXECUTORS.remove(name);
        if (meta == null) {
            return;
        }
        //关闭老的
        meta.getWrapper().shutdown();
        if (!meta.getSource().isShutdown()) {
            meta.getSource().shutdown();
        }
    }

    private static ExecutorStatus buildExecutorStatus(ThreadPoolExecutor executor) {
        if (executor == null) {
            return null;
        }
        ExecutorStatus status = new ExecutorStatus();
        status.setCoreSize(executor.getCorePoolSize());
        status.setMaxSize(executor.getMaximumPoolSize());
        status.setCurrentNum(executor.getPoolSize());
        status.setActiveNum(executor.getActiveCount());
        status.setHistoryMaxNum(executor.getLargestPoolSize());
        status.setRecycleCore(executor.allowsCoreThreadTimeOut());
        status.setKeepAlive((int) executor.getKeepAliveTime(TimeUnit.SECONDS));
        status.setWaitTaskNum(executor.getQueue().size());
        status.setShutdown(executor.isShutdown());
        status.setTerminated(executor.isTerminated());
        status.setRejectHandler(executor.getRejectedExecutionHandler().getClass().getName());
        return status;
    }


    public static class Meta {
        private ThreadPoolExecutor source;
        private ExecutorService wrapper;

        public Meta(ThreadPoolExecutor source, ExecutorService executorService) {
            this.source = source;
            this.wrapper = executorService;
        }

        public ThreadPoolExecutor getSource() {
            return source;
        }

        public void setSource(ThreadPoolExecutor source) {
            this.source = source;
        }

        public ExecutorService getWrapper() {
            return wrapper;
        }

        public void setWrapper(ExecutorService wrapper) {
            this.wrapper = wrapper;
        }
    }


    public static class ExecutorStatus {
        /**
         * 核心线程数
         */
        private int coreSize;
        /**
         * 最大线程数
         */
        private int maxSize;

        /**
         * 当前线程数
         */
        private int currentNum;
        /**
         * 当前在干活的线程数
         */
        private int activeNum;

        /**
         * 历史最大线程数
         */
        private int historyMaxNum;

        /**
         * 等待执行的任务数
         */
        private int waitTaskNum;

        /**
         * 拒绝策略
         */
        private String rejectHandler;

        /**
         * 回收时长
         * 单位秒
         */
        private int keepAlive;

        /**
         * 是否回收核心线程池
         */
        private boolean recycleCore;


        /**
         * 停止
         */
        private boolean shutdown;

        /**
         * 完毕
         */
        private boolean terminated;

        public int getCoreSize() {
            return coreSize;
        }

        public void setCoreSize(int coreSize) {
            this.coreSize = coreSize;
        }

        public int getMaxSize() {
            return maxSize;
        }

        public void setMaxSize(int maxSize) {
            this.maxSize = maxSize;
        }

        public int getCurrentNum() {
            return currentNum;
        }

        public void setCurrentNum(int currentNum) {
            this.currentNum = currentNum;
        }

        public int getActiveNum() {
            return activeNum;
        }

        public void setActiveNum(int activeNum) {
            this.activeNum = activeNum;
        }

        public int getHistoryMaxNum() {
            return historyMaxNum;
        }

        public void setHistoryMaxNum(int historyMaxNum) {
            this.historyMaxNum = historyMaxNum;
        }

        public int getKeepAlive() {
            return keepAlive;
        }

        public void setKeepAlive(int keepAlive) {
            this.keepAlive = keepAlive;
        }

        public boolean isRecycleCore() {
            return recycleCore;
        }

        public void setRecycleCore(boolean recycleCore) {
            this.recycleCore = recycleCore;
        }

        public int getWaitTaskNum() {
            return waitTaskNum;
        }

        public void setWaitTaskNum(int waitTaskNum) {
            this.waitTaskNum = waitTaskNum;
        }

        public boolean isShutdown() {
            return shutdown;
        }

        public void setShutdown(boolean shutdown) {
            this.shutdown = shutdown;
        }

        public boolean isTerminated() {
            return terminated;
        }

        public void setTerminated(boolean terminated) {
            this.terminated = terminated;
        }

        public String getRejectHandler() {
            return rejectHandler;
        }

        public void setRejectHandler(String rejectHandler) {
            this.rejectHandler = rejectHandler;
        }

        @Override
        public String toString() {
            return "ExecutorStatus{" +
                    "coreSize=" + coreSize +
                    ", maxSize=" + maxSize +
                    ", currentNum=" + currentNum +
                    ", activeNum=" + activeNum +
                    ", historyMaxNum=" + historyMaxNum +
                    ", waitTaskNum=" + waitTaskNum +
                    ", rejectHandler='" + rejectHandler + '\'' +
                    ", keepAlive=" + keepAlive +
                    ", recycleCore=" + recycleCore +
                    ", shutdown=" + shutdown +
                    ", terminated=" + terminated +
                    '}';
        }
    }

}
